package logic

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"gitee.com/jmdvirus/jkgo/jk/jklog"
	"github.com/google/uuid"
	"github.com/larksuite/oapi-sdk-go/v3"
	"github.com/larksuite/oapi-sdk-go/v3/core"
	larkbitable "github.com/larksuite/oapi-sdk-go/v3/service/bitable/v1"
	"github.com/larksuite/oapi-sdk-go/v3/service/wiki/v2"
	"io"
	"net/http"
	"os"
)

type FeiShuConfig struct {
	BaseUrl          string `json:"baseUrl"`
	AppID            string `json:"appId"`
	AppSecret        string `json:"appSecret"`
	StudyWordToken   string `json:"studyWordToken"`
	StudyWordTableId string `json:"studyWordTableId"`
}

type FeiShuTenantToken struct {
	TenantAccessToken string `json:"tenant_access_token"`
	Expire            int64  `json:"expire"`
}

type FeiShuOperation struct {
	cfg               FeiShuConfig
	tenantToken       FeiShuTenantToken
	studyWordReqToken string
}

var feishu_op *FeiShuOperation

func NewFeiShuOperation() *FeiShuOperation {
	return &FeiShuOperation{}
}

func (f *FeiShuOperation) Load(file string) error {
	fd, err := os.Open(file)
	defer fd.Close()
	if err != nil {
		return err
	}
	data, err := io.ReadAll(fd)
	if err != nil {
		return err
	}
	var cfg FeiShuConfig
	err = json.Unmarshal(data, &cfg)
	if err != nil {
		return err
	}
	f.cfg = cfg
	jklog.L().Infoln("FeiShuOperation baseUrl: ", cfg.BaseUrl)

	return nil
}

func init() {
	feishu_op = NewFeiShuOperation()
	err := feishu_op.Load("./etc/feishu.json")
	if err != nil {
		jklog.L().Errorln(err)
	}
	jklog.L()
}

func (f *FeiShuOperation) fetchTenantToken() error {
	requestUrl := f.cfg.BaseUrl + "/auth/v3/tenant_access_token/internal"
	reqDataStruct := struct {
		AppId     string `json:"app_id"`
		AppSecret string `json:"app_secret"`
	}{f.cfg.AppID, f.cfg.AppSecret}

	reqData, err := json.Marshal(reqDataStruct)
	if err != nil {
		return err
	}
	req, err := http.NewRequest("POST", requestUrl, bytes.NewBuffer(reqData))
	if err != nil {
		return err
	}
	req.Header.Set("Content-Type", "application/json")
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	respData, err := io.ReadAll(resp.Body)
	if err != nil {
		return err
	}

	err = json.Unmarshal(respData, &f.tenantToken)
	if err != nil {
		return err
	}
	jklog.L().Infoln("FeiShuOperation tenantToken get done, ", f.tenantToken)
	return nil
}

func (f *FeiShuOperation) getNodeToken() error {

	// 创建 Client
	client := lark.NewClient(f.cfg.AppID, f.cfg.AppSecret)
	// 创建请求对象
	req := larkwiki.NewGetNodeSpaceReqBuilder().
		Token(f.cfg.StudyWordToken).
		ObjType(`wiki`).
		Build()

	// 发起请求
	resp, err := client.Wiki.V2.Space.GetNode(context.Background(), req)

	// 处理错误
	if err != nil {
		fmt.Println(err)
		return err
	}

	// 服务端错误处理
	if !resp.Success() {
		fmt.Printf("logId: %s, error response: \n%s", resp.RequestId(), larkcore.Prettify(resp.CodeError))
		return err
	}

	// 业务处理
	f.studyWordReqToken = *resp.Data.Node.ObjToken
	fmt.Println("get word node token done, ", f.studyWordReqToken)
	return nil
}

func (f *FeiShuOperation) addWordRecord(data map[string]interface{}) error {

	err := f.getNodeToken()
	if err != nil {
		return err
	}

	newUUID := uuid.New().String()
	jklog.L().Infoln("new uuid: ", newUUID)

	client := lark.NewClient(f.cfg.AppID, f.cfg.AppSecret)
	// 创建请求对象
	req := larkbitable.NewCreateAppTableRecordReqBuilder().
		AppToken(f.studyWordReqToken).
		TableId(f.cfg.StudyWordTableId).
		UserIdType(`open_id`).
		ClientToken(newUUID).
		IgnoreConsistencyCheck(true).
		AppTableRecord(larkbitable.NewAppTableRecordBuilder().
			Fields(data).
			Build()).
		Build()

	// 发起请求
	resp, err := client.Bitable.V1.AppTableRecord.Create(context.Background(), req)

	// 处理错误
	if err != nil {
		fmt.Println(err)
		return err
	}

	// 服务端错误处理
	if !resp.Success() {
		fmt.Printf("logId: %s, error response: \n%s", resp.RequestId(), larkcore.Prettify(resp.CodeError))
		return err
	}

	// 业务处理
	fmt.Println("record add done")
	return nil
}

func AddWordRecord(data map[string]interface{}) error {
	return feishu_op.addWordRecord(data)
}
